package com.castle.fortress.admin.dify.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alipay.api.domain.Contract;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.castle.fortress.admin.contract.info.entity.ContractEntity;
import com.castle.fortress.admin.contract.info.service.ContractService;
import com.castle.fortress.admin.dify.model.*;
import com.castle.fortress.admin.dify.service.ContractReviewInfoService;
import com.castle.fortress.admin.dify.service.ContractReviewResultService;
import com.castle.fortress.admin.dify.service.FileUploadService;
import com.castle.fortress.admin.rule.rule.dto.RuleDto;
import com.castle.fortress.admin.rule.rule.service.RuleService;
import com.castle.fortress.common.utils.ConvertUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CompletionException;

@Slf4j
@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Value("${file.upload.url:http://103.146.51.86/v1/files/upload}")
    private String fileUploadUrl;

    @Value("${chat.messages.url:http://103.146.51.86/v1/chat-messages}")
    private String chatMessagesUrl;

    @Value("${file.upload.token:app-Whz0Qr6EX3n4FIYYTCtb3HbT}")
    private String fileUploadToken;

    @Value("${chat.messages.token:app-Whz0Qr6EX3n4FIYYTCtb3HbT}")
    private String chatMessagesToken;

    @Value("${chat.messages.token:app-4jX7eSC8aIplFHboDiVGK2g3}")
    private String checkFileToken;

    @Autowired
    private ContractReviewResultService contractReviewResultService;

    @Autowired
    RuleService ruleService;

    @Autowired
    private ContractReviewInfoService contractReviewInfoService;
    @Autowired
    private ContractService contractService;


    private final ObjectMapper objectMapper;
    private final ExecutorService executorService;

    public FileUploadServiceImpl(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        this.executorService = Executors.newCachedThreadPool();
    }

    /**
     * 上传文件
     *
     * @param file 文件
     * @param userId 用户ID
     * @return 文件上传响应
     */
    @Override
    public FileUploadResponse uploadFile(MultipartFile file, String userId,String fileUrl) {
        return uploadFileInternal(file, userId, fileUploadUrl, fileUploadToken,fileUrl);
    }

    /**
     * 分析合同文件并返回基本信息
     * 该方法会调用AI接口解析合同内容，提取关键信息
     *
     * @param fileId 已上传的文件ID
     * @param userId 用户ID
     * @return 合同分析结果
     */
    public ContractAnalysisResult analyzeContractInfo(String fileId, String userId) {
        try {
            // 构建请求体
            ObjectNode requestBody = objectMapper.createObjectNode();
            // 输入参数，可以根据需要添加特定的分析指令
            ObjectNode inputs = requestBody.putObject("inputs");
            // 设置查询指令为"合同信息"，用于提取合同的基本信息
            requestBody.put("query", "合同信息");
            // 使用流式响应模式，实时返回分析结果
            requestBody.put("response_mode", "blocking");
            // 对话ID，新会话设置为空
            requestBody.put("conversation_id", "");
            requestBody.put("user", userId);

            // 设置要分析的文件信息
            ArrayNode filesArray = requestBody.putArray("files");
            ObjectNode fileObject = filesArray.addObject();
            fileObject.put("type", "document");
            fileObject.put("transfer_method", "remote_url");
            fileObject.put("url", fileId);




            log.info("Sending contract analysis request for file: {}", fileId);

            // 发送请求到AI分析接口
            String response = HttpRequest.post(chatMessagesUrl)
                    .header("Authorization", "Bearer " + chatMessagesToken)
                    .header("Accept", "application/json")
                    .header("Content-Type", "application/json;charset=UTF-8")
                    .body(requestBody.toString())
                    .execute()
                    .body();


            log.info("Received contract analysis response for file: {}", fileId);

            // 解析响应
            ContractAnalysisResponse analysisResponse = objectMapper.readValue(response, ContractAnalysisResponse.class);
            // 解析answer字段中的合同分析结果
            return objectMapper.readValue(analysisResponse.getAnswer(), ContractAnalysisResult.class);
        } catch (Exception e) {
            log.error("Failed to analyze contract information", e);
            throw new RuntimeException("Failed to analyze contract information: " + e.getMessage());
        }
    }

    /**
     * 内部文件上传方法
     */
    private FileUploadResponse uploadFileInternal(MultipartFile file, String userId, String url, String token,String fileUrl) {
        try {
           String correctFileName ="";
            if(file!=null){
                // 处理文件名编码
                String originalFilename = file.getOriginalFilename();
                 correctFileName = new String(originalFilename.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                log.info("Original filename: {}, Corrected filename: {}", originalFilename, correctFileName);

            }





            // 创建文件上传的Future
            CompletableFuture<FileUploadResponse> uploadFuture = CompletableFuture.supplyAsync(() -> {
                try {
                    HttpRequest httpRequest = HttpRequest.post(url)
                            .header("Authorization", "Bearer " + token)
                            .header("Accept", "application/json")
                            .header("Accept-Charset", "UTF-8")
                            .header("Content-Type", "multipart/form-data;charset=UTF-8")
                            .form("user", userId)
                            .form("inputs", "{\"fileUrl\":\"" + fileUrl + "\"}")
                            .charset(StandardCharsets.UTF_8);


                    if(file!=null){
                      //  httpRequest.form("file", file.getBytes(), correctFileName);
                    }

                    String response = httpRequest
                                        .execute()
                                        .body();



                    return objectMapper.readValue(response, FileUploadResponse.class);
                } catch (Exception e) {
                    throw new CompletionException(e);
                }
            });

            // 等待文件上传完成，获取文件ID后立即开始分析
            FileUploadResponse uploadResponse = uploadFuture.get(30, TimeUnit.SECONDS);
            
            // 创建合同分析的Future
            CompletableFuture<ContractAnalysisResult> analysisFuture = CompletableFuture.supplyAsync(() -> 
                this.analyzeContractInfo(uploadResponse.getId(), userId.toString())
            );

            // 等待分析完成
            ContractAnalysisResult analysisResult = analysisFuture.get(30, TimeUnit.SECONDS);
            uploadResponse.setInfo(analysisResult);
            
            return uploadResponse;

        } catch (TimeoutException e) {
            log.error("Operation timed out", e);
            throw new RuntimeException("Operation timed out: " + e.getMessage());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("Operation was interrupted", e);
            throw new RuntimeException("Operation was interrupted: " + e.getMessage());
        } catch (ExecutionException e) {
            log.error("Operation failed", e.getCause());
            throw new RuntimeException("Operation failed: " + e.getCause().getMessage());
        } catch (Exception e) {
            log.error("Unexpected error", e);
            throw new RuntimeException("Unexpected error: " + e.getMessage());
        }
    }


    /***
     *
     * @param request 合同审查请求参数，包含文件ID、用户ID、审查立场和审查力度等信息
     * @return
     */


    @Override
    public SseEmitter reviewContract(ContractReviewRequest request) {

        String responseMode =  request.getResponseMode()!=null?request.getResponseMode():"streaming"    ;

        SseEmitter emitter = new SseEmitter(-1L); // 无超时

        // 在主线程中获取 Subject
        Subject currentSubject = null;
        try {
            currentSubject = SecurityUtils.getSubject();
        } catch (Exception e) {
            log.warn("Unable to get current subject, proceeding without security context");
        }

        final Subject finalSubject = currentSubject;

        // 异步执行合同审查任务
        executorService.execute(() -> {
            try {
                // 在异步线程中绑定 Subject
                if (finalSubject != null) {
                  //  ThreadContext.bind(finalSubject);
                }

                // 构建请求体
                ObjectNode requestBody = objectMapper.createObjectNode();

                // 设置输入参数

                ObjectNode inputs = requestBody.putObject("inputs");
                inputs.put("standpoint", request.getStandpoint());
                inputs.put("reviewScale", request.getReviewScale());

                // 设置其他参数
                requestBody.put("query", request.getQuery());
                requestBody.put("response_mode", responseMode);



                requestBody.put("conversation_id", "");
                requestBody.put("user", request.getUserId());

                // 设置文件信息
                ArrayNode filesArray = requestBody.putArray("files");
                ObjectNode fileObject = filesArray.addObject();
                fileObject.put("type", "document");
                fileObject.put("transfer_method", "remote_url");
                fileObject.put("url", request.getFileUrl());

                log.info("Request body: {}", requestBody.toString());  // 打印请求内容

                // 发送请求并处理SSE响应
                HttpResponse response = HttpRequest.post(chatMessagesUrl)
                        .header("Authorization", "Bearer " + checkFileToken)
                        .header("Accept", "text/event-stream")
                        .header("Cache-Control", "no-cache")
                        .header("Connection", "keep-alive")
                        .header("Content-Type", "application/json;charset=UTF-8")
                        .body(requestBody.toString())
                        .execute();


                String body2 = response.body();

                DefaultSecurityManager securityManager = new DefaultSecurityManager();
                SecurityUtils.setSecurityManager(securityManager);



                // 读取响应流 并发送SSE事件
                try (InputStream inputStream = response.bodyStream();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {

                    String line;

                    while ((line = reader.readLine()) != null) {

                        if (line.startsWith("data:")) {
                            String data = line.substring(5).trim();

                            log.info("Received SSE data: {}", data);  // 打印接收到的数据
                            emitter.send(data);
                        }


                    }


                }

                emitter.complete();
                log.info("Contract review completed for file: {}", request.getFileId());



            } catch (Exception e) {
                log.error("Error during contract review", e);
                try {
                    // 打印详细的错误信息
                    log.error("Error details: ", e);
                    emitter.send(SseEmitter.event()
                        .data("Error: " + e.getMessage())
                        .build());
                } catch (Exception sendError) {
                    log.error("Failed to send error to client", sendError);
                }
                emitter.completeWithError(e);
            } finally {
                // 清理线程上下文
               // ThreadContext.unbind();
            }
        });

        return emitter;
    }



    @Override
    public ReviewRulesResults reviewContractBlocking(ContractReviewRequest request,Long infoID) {

        request.setReviewInfoId(infoID);


        String responseMode =  request.getResponseMode()!=null?request.getResponseMode():"streaming";

        SseEmitter emitter = new SseEmitter(-1L); // 无超时


        String riskId = request.getRiskId()+"";

        RuleDto byIdExtends = ruleService.getByIdExtends(Long.valueOf(riskId));
        String ruleDesc = byIdExtends.getRuleDesc();


        // 在主线程中获取 Subject
        Subject currentSubject = null;
        try {
            currentSubject = SecurityUtils.getSubject();
        } catch (Exception e) {
            log.warn("Unable to get current subject, proceeding without security context");
        }

        final Subject finalSubject = currentSubject;

        // 异步执行合同审查任务

        // 在异步线程中绑定 Subject
        if (finalSubject != null) {
            //  ThreadContext.bind(finalSubject);
        }

        // 构建请求体
        ObjectNode requestBody = objectMapper.createObjectNode();

        // 设置输入参数

        ObjectNode inputs = requestBody.putObject("inputs");
        inputs.put("standpoint", request.getStandpoint());
        inputs.put("reviewScale", request.getReviewScale());

        // 设置其他参数
        requestBody.put("query", ruleDesc);
        requestBody.put("response_mode", responseMode);



        requestBody.put("conversation_id", "");
        requestBody.put("user", request.getUserId());

        // 设置文件信息
        ArrayNode filesArray = requestBody.putArray("files");
        ObjectNode fileObject = filesArray.addObject();
//        fileObject.put("type", "document");
//        fileObject.put("transfer_method", "local_file");
//        fileObject.put("upload_file_id", request.getFileId());
//        fileObject.put("upload_file_id", request.getFileId());
//

        fileObject.put("type", "document");
        fileObject.put("transfer_method", "remote_url");
        fileObject.put("url", request.getFileUrl());



        log.info("Request body: {}", requestBody.toString());  // 打印请求内容

        // 发送请求并处理SSE响应
        HttpResponse response = HttpRequest.post(chatMessagesUrl)
                .header("Authorization", "Bearer " + checkFileToken)
                .header("Accept", "text/event-stream")
                .header("Cache-Control", "no-cache")
                .header("Connection", "keep-alive")
                .header("Content-Type", "application/json;charset=UTF-8")
                .body(requestBody.toString())
                .execute();


        String body2 = response.body();

        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        SecurityUtils.setSecurityManager(securityManager);


        if(request.getResponseMode().equals("blocking")){
            try {
                // 解析响应
                ContractAnalysisResponse analysisResponse = objectMapper.readValue(body2, ContractAnalysisResponse.class);
                String answer = analysisResponse.getAnswer();
                
                // 使用新的格式化方法处理 answer
                String formattedAnswer = formatAnswerString(answer);
                
                // 使用格式化后的答案进行反序列化
                List<ContractReviewRequestResult> contractReviewResults = objectMapper.readValue(
                    formattedAnswer,
                    objectMapper.getTypeFactory().constructCollectionType(List.class, ContractReviewRequestResult.class)
                );

                ReviewRulesResults reviewRulesResults = this.tranformRulesRequest(contractReviewResults, byIdExtends);


                this.saveReviewResult(reviewRulesResults,request);


                return reviewRulesResults;

            } catch (JsonProcessingException e) {
                log.error("Error processing contract review: {}", e.getMessage());
                log.debug("Error details:", e);
            }
        }

        return new ReviewRulesResults();
    }






    void saveReviewResult(ReviewRulesResults reviewRulesResults,ContractReviewRequest request){


        QueryWrapper<ContractReviewInfo> wrapper=new QueryWrapper();
        wrapper.eq( "contract_id",request.getContractId());
        wrapper.eq( "rule_id",request.getRuleId());

        List<ContractReviewInfo> list = contractReviewInfoService.list(wrapper);

        ContractReviewInfo contractReviewInfo=null;
        if(CollUtil.isNotEmpty(list)){
            contractReviewInfo = list.get(0);
        }
        //修改审查项为审查完成，新增审查结果


        UpdateWrapper<ContractReviewInfo> updateWrapper=new UpdateWrapper();
        updateWrapper.eq( "review_info_id",request.getReviewInfoId());
       // updateWrapper.eq( "rule_id",request.getRuleId());
        updateWrapper.set("review_status","completed");
        updateWrapper.set("review_end_time", DateUtil.now());

        UpdateWrapper<ContractEntity> updateWrapper2=new UpdateWrapper();
        updateWrapper2.eq( "contract_id",request.getContractId());
        // updateWrapper.eq( "rule_id",request.getRuleId());
        updateWrapper2.set("review_status","completed");
        contractService.update(updateWrapper2);



      contractReviewInfoService.update(updateWrapper);


        ContractReviewResult contractReviewResult = ConvertUtil.transformObj(reviewRulesResults, ContractReviewResult.class);
        //contractReviewResult.setReviewId(result.getReviewId());
        //生成long类型的uuid
        contractReviewResult.setResultId(UUID.randomUUID().getMostSignificantBits());
        contractReviewResult.setReviewId(request.getReviewId());
        contractReviewResult.setReviewInfoId(request.getReviewInfoId());

        //将result.getSubRisks() 转化为json
        try {
            contractReviewResult.setRisks(new ObjectMapper().writeValueAsString(reviewRulesResults.getSubRisks()));
        }   catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        contractReviewResult.setIsRisk("0");
        if(contractReviewResult.getRisks().length()>0){
            contractReviewResult.setIsRisk("1");
        }


        contractReviewResult.setContractId(request.getContractId());

        contractReviewResultService.save(contractReviewResult);

    }


    public ReviewRulesResults tranformRulesRequest(List<ContractReviewRequestResult> contractReviewResult,RuleDto rule){


        ReviewRulesResults reviewRulesResults = new ReviewRulesResults();

       // contractReviewResult.setRiskId(rule.getId().toString());
        reviewRulesResults.setRiskLevel(rule.getRiskLevel());
       // reviewRulesResults.set(rule.getRiskLevel());
        //contractReviewResult.setRiskExplain(rule.getRiskName());
        reviewRulesResults.setExamineBrief(rule.getRuleDesc());
        reviewRulesResults.setSubRuleTitle(rule.getRuleName());
       // reviewRulesResults.setExamineResult(rule.getRuleType());

        reviewRulesResults.setSubRisks(contractReviewResult);
        reviewRulesResults.setSubRiskNum(contractReviewResult.size());


        return reviewRulesResults;
    }






    /**
     * 获取合同审查的查询内容
     */
    private String getContractReviewQuery() {
        return "（1）审查主体信息是否完整、准确：" +
                "①自然人的主要信息为：姓名、性别、住所地、身份证号码、联系方式、出生日期、单位及职务等；" +
                "②法人或者其他组织的主要信息为：法人名称或者其他组织名称、住所地。法定代表人姓名（或者负责人姓名）、统一社会信用代码、银行账户、银行账号等；" +
                "③如为个体工商户，则主体应列个体工商户字号，同时列明经营者个人身份信息； " +
                "（2）审查是否具备主体资格。" +
                "①自然人是否具备完全民事行为能力，如不具备，是否经过其监护人的追认；" +
                "②法人或其他组织而言，主要审查其是否依法设立并有效存续；如果签订合同的主体是法人的分支机构，必须依法登记取得营业执照，否则则需要法人授权，而未经特别授权，法人的职能部门等都不具有签订合同的主体资格。 " +
                "（3）某些特殊行业实行特许经营的，还需要合同主体具备特别的资格要求，例如建设工程承包人需取得相应的建筑工程施工资质，医疗单位需取得相应许可证（医疗机构许可证），具体审核时需考虑是否涉及特许经营行业，是否需参照相关特许经营的法律法规的规定。 " +
                "（4）合同主体不属于禁止从事本合同所涉及的民事行为的主体，例如一是机关法人，二是以公益为目的的非营利法人，三是非法人组织等不得作为保证人；股东及合伙人的被限制同目标企业交易等；";
    }

    /**
     * 格式化并解析 AI 返回的 answer 字符串
     * 处理可能包含的 Markdown 格式和特殊字符
     *
     * @param answer AI 返回的原始 answer 字符串
     * @return 格式化后的 JSON 字符串
     */
    private String formatAnswerString(String answer) {
        if (answer == null || answer.trim().isEmpty()) {
            return "[]";
        }

        try {
            // 1. 移除可能的 Markdown 代码块标记
            answer = answer.replaceAll("```json\\s*", "")
                          .replaceAll("```\\s*", "");

            // 2. 检查是否是有效的 JSON 数组格式
            if (!answer.trim().startsWith("[")) {
                // 如果不是数组格式，尝试查找 JSON 数组部分
                int startIndex = answer.indexOf("[");
                int endIndex = answer.lastIndexOf("]");
                
                if (startIndex >= 0 && endIndex >= 0) {
                    answer = answer.substring(startIndex, endIndex + 1);
                } else {
                    // 如果找不到数组标记，可能是单个对象，将其包装为数组
                    if (answer.trim().startsWith("{")) {
                        answer = "[" + answer + "]";
                    } else {
                        return "[]";
                    }
                }
            }

            // 3. 验证 JSON 格式是否有效
            objectMapper.readTree(answer);
            
            return answer.trim();
        } catch (Exception e) {
            log.error("Error formatting answer string: {}", e.getMessage());
            log.debug("Original answer: {}", answer);
            return "[]";
        }
    }
}